home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / comm / fido / xprfts072.lzh / sendX.c < prev    next >
C/C++ Source or Header  |  1992-11-24  |  18KB  |  583 lines

  1. /*
  2.     $Header: Welmat:src/Welmat/xprfts/RCS/sendX.c,v 1.2 92/11/24 23:40:44 rwm Exp Locker: rwm $
  3.  
  4.     send a file with TeLink/Xmodem.
  5.  
  6.     Copyright (C) 1988,1989,1990 Michael Richardson
  7.     Copyright (C) 1992 Russell McOrmond
  8.  
  9.     This program is free software; you can redistribute it and/or modify
  10.     it under the terms of the GNU General Public License as published by
  11.     the Free Software Foundation; either version 2 of the License, or
  12.     (at your option) any later version.
  13.  
  14.     This program is distributed in the hope that it will be useful,
  15.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.     GNU General Public License for more details.
  18.  
  19.     You should have received a copy of the GNU General Public License
  20.     along with this program; if not, write to the Free Software
  21.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23.  */
  24.  
  25. #ifdef RCSID
  26. static char RCSid[]="$Id: sendX.c,v 1.2 92/11/24 23:40:44 rwm Exp Locker: rwm $";
  27. #endif
  28.  
  29. #include <proto/all.h>
  30. #include <exec/types.h>
  31. #include <exec/memory.h>
  32. #include <ctype.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <time.h>
  37. #include "xproto.h"
  38. #include "xmodem.h"
  39. #include "xprfts.h"
  40.  
  41.  
  42. long sendXFiles(struct Vars *v)
  43. {
  44.   long stateinfo,lasterr=OK,state=GOTACK,count=10,mdm7count=10;
  45.   char filename[256],temp[2],temp1[51];
  46.   
  47.   /* send a TSYNCH to start off the transfer */
  48.   temp[0]=TSYNCH;
  49.   xpr_swrite(&v->io,temp,1);
  50.   updmsg(v,"TSYNCH!");
  51.   while(state==GOTACK) {
  52.     state=xpr_sread(&v->io,temp,1,4000000);
  53.  
  54.     /* 1 char, 0 timeout, or -1 carrier drop */
  55.     if(state==0 && count--) {
  56.       temp[0]=TSYNCH;
  57.       xpr_swrite(&v->io,temp,1);
  58.       updmsg(v,"TSYNCH!");
  59.       state=GOTACK;
  60.     }
  61.     if(state==1)
  62.       if((temp[0]&0xff)==NAK) state=GOTNAK;
  63.       else if ((temp[0]&0xff)==CNAK) state=GOTCNAK;
  64.       else state=GOTACK;
  65.   }
  66.   if(!state) { /* no characters came back */
  67.     updmsg(v,"Other end didn't start transfer");
  68.     return(ERROR);
  69.   }
  70.   else if(state==-1) { /* dropped carrier */
  71.     updmsg(v,"Dropped Carrier");
  72.     return(NODCD);
  73.   }
  74.  
  75.   /* clear the filename to receive the new file */
  76.   filename[0]='\0';
  77.  
  78.   stateinfo=xpr_ffirst(&v->io,filename,"");
  79.   while(stateinfo) {
  80.     if (v->option_7=='N' || 
  81.        (!(v->outfiles) && (v->option_m=='Y')) || /* mail bundle */
  82.        (v->option_c=='Y' && (state==GOTCNAK))) { /* allow mdm7 skipping */
  83.       lasterr=sendXFile(v,filename);
  84.     } else {
  85.       lasterr=sendmdm7(v,filename);
  86.     }
  87.  
  88.     if(lasterr==MDM7BAD && (mdm7count--));
  89.     else if(lasterr) {
  90.       updstatus(v,filename,XPRS_FAILURE);
  91.       stateinfo=NULL;
  92.     }
  93.     else {
  94.       updstatus(v,filename,XPRS_SUCCESS);
  95.       v->outfiles++;
  96.       filename[0]='\0';
  97.       lasterr=stateinfo=xpr_fnext(&v->io,stateinfo,filename,"");
  98.     }
  99.  
  100.     /* wait 1 second and clear buffer */
  101.     (void)xpr_sread(&v->io,temp1,50,1000000);
  102.  
  103.     /* wait for poll for more files... */
  104.     state=GOTACK;
  105.     while(state==GOTACK) {
  106.       state=xpr_sread(&v->io,temp,1,10000000);
  107.  
  108.       /* 1 char, 0 timeout, or -1 carrier drop */
  109.       if(state==1)
  110.         if((temp[0]&0xff)==NAK) state=GOTNAK;
  111.         else if ((temp[0]&0xff)==CNAK) state=GOTCNAK;
  112.         else state=GOTACK;
  113.     }
  114.     if(!state) { /* no characters came back */
  115.       updmsg(v,"Other end didn't want more files");
  116.       return(ERROR);
  117.     }
  118.     else if(state==-1) { /* dropped carrier */
  119.       updmsg(v,"Dropped Carrier");
  120.       return(NODCD);
  121.     }
  122.   }
  123.  
  124.   if (lasterr==OK) {
  125.     count=50;
  126.     state=0;
  127.     while(--count>0 && (state!=-1) &&
  128.        ((state==0) || (((temp[0]&0xff)!=ENQ) && ((temp[0]&0xff)!=TSYNCH) &&
  129.            ((temp[0]&0xff)!=ACK)))) {
  130.  
  131.       if((state==0) || ((temp[0]&0xff)==NAK) || ((temp[0]&0xff)==CNAK)) {
  132.         temp1[0]=EOT;
  133.         xpr_swrite(&v->io,temp1,1);
  134.         updmsg(v,"EOTing!");
  135.         count=count-4; /* timeout/NAK's cause quicker timeout than line noise */ 
  136.       }
  137.       state=xpr_sread(&v->io,temp,1,2000000);
  138.       SPrintF(v->scratch,"InEOT:state = %ld, count = %ld char: %ld",state,
  139.                          count,(temp[0]&0xff));
  140.       updmsg(v,v->scratch);
  141.     }
  142.     SPrintF(v->scratch,"AfterEOT:state = %ld, count = %ld char: %ld",state,
  143.                        count,(temp[0]&0xff));
  144.     updmsg(v,v->scratch);
  145.  
  146.     if(state==NODCD) {
  147.       lasterr=NODCD;
  148.     }
  149.     else if(state==0);  /* timeout */
  150.     else if((temp[0]&0xff)==ENQ) {
  151.       /* Bark File requests */
  152.       temp1[0]=ETB;
  153.       xpr_swrite(&v->io,temp1,1);
  154.     }
  155.     else if((temp[0]&0xff)==TSYNCH);
  156.     else if((temp[0]&0xff)==ACK);
  157.     else 
  158.       lasterr=ERROR;
  159.   }
  160.   return(lasterr);
  161. }
  162.  
  163. void makeTelinkHeader(register unsigned char *buf,
  164.                       char *filename,long size,long time, char mode)
  165. {
  166.   /*mode  0=Telink, 1=Sealink, 2=Sealink(LargeNames) */
  167.  
  168.   memset(buf,0,128);
  169. /*      3   3 |     File Length, least significant byte       |  0    0
  170.               +-----------------------------------------------+
  171.         4   4 | File Length, second to least significant byte |  1    1
  172.               +-----------------------------------------------+
  173.         5   5 |  File Length, second to most significant byte |  2    2
  174.               +-----------------------------------------------+
  175.         6   6 |      File Length, most significant byte       |  3    3*/
  176.   { register char *s;
  177.     s=(char *)&size;
  178.     *buf++=s[3];
  179.     *buf++=s[2];
  180.     *buf++=s[1];
  181.     *buf++=s[0];
  182.   }
  183. /*            +-----------------------------------------------+
  184.         7   7 |            Creation Time of File              |  4    4
  185.               |                "DOS Format"                   |
  186.               +-----------------------------------------------+
  187.         9   9 |            Creation Date of File              |  6    6
  188.               |                "DOS Format"                   |
  189.               +-----------------------------------------------+*/
  190.  
  191.   /* The above is BOGUS. We seem to be doing a SeaLink block, so
  192.      we have to do Unix timestamps... */
  193.  
  194.    if(mode==0) {
  195.      register struct tm *now;
  196.      register unsigned short temp;
  197.  
  198.      now=localtime(&time);
  199.      temp=(now->tm_hour<<11)|(now->tm_min<<5)|(now->tm_sec/2);
  200.      *buf++=temp&0xff;
  201.      *buf++=temp>>8;
  202.      temp=((now->tm_year-80)<<9)|(now->tm_mon<<5)|(now->tm_mday);
  203.      *buf++=temp&0xff;
  204.      *buf++=temp>>8;
  205.    }
  206.    else {
  207.      register char *s;
  208.      /* AmigaDOS Times are from 1978, Unix times from 1970. */
  209.      time=time+(60*60*24*(365*8+2));
  210.  
  211.      s=(char *)&time;
  212.      *buf++=s[3];
  213.      *buf++=s[2];
  214.      *buf++=s[1];
  215.      *buf++=s[0];
  216.    }
  217.  
  218.  
  219. /*     11   B |                 File  Name                    |  8    8
  220.               ~                  16 chars                     ~
  221.               |        left justified  blank filled           |
  222.               +-----------------------------------------------+
  223.        27  1B |                    00H                        | 24   18
  224.               +-----------------------------------------------+
  225.        28  1C |            Sending Program Name               | 25   19
  226.               ~                  16 chars                     ~
  227.               |         left justified  Null filled           |
  228.               +-----------------------------------------------+
  229. */
  230.  
  231.    { register int i;
  232.  
  233.      /* copy filename*/
  234.      for(i=0;*filename!='\0' && i<((mode=2) ? 32 : 16);*buf++=*filename++) i++;
  235.  
  236.      /* blank fill */
  237.      if (i<16) {
  238.        for(;i<16;i++) *++buf=' ';
  239.        *buf++=0;
  240.        strncpy(buf,"Welmat",15);
  241.        buf=buf+15;
  242.      } else {
  243.        for(;i<32;i++) *++buf=' ';
  244.      }
  245.    }
  246.  
  247.    if(mode==0) 
  248.       buf[44]=1;  /* If we're doing telink, say that we're doing CRC! */
  249.                   /* otherwise leave it as a 0 to indicate no compatability
  250.                      with SLO */
  251. /*
  252.               +-----------------------------------------------+
  253.        44  2B |            01H (for CRC) or 00H               | 41   29
  254.               +-----------------------------------------------+
  255.        45  2C |                    fill                       | 42   2A
  256.               ~                  86 bytes                     ~
  257.               |                  all zero                     |
  258.               +-----------------------------------------------+
  259. */
  260. }
  261.  
  262. void sendXPacket(struct Vars *v,BYTE ckmode,block *lastPacket,int blocknum)
  263. {
  264.   char *buf;
  265.   int i;
  266.  
  267.   lastPacket->bl_blocknum=(blocknum&0xff);
  268.   lastPacket->bl_blockcom=(~(blocknum&0xff));
  269.  
  270.   if(!ckmode) {
  271.     int ck;
  272.  
  273.     lastPacket->bl_start=SYN;
  274.     buf=lastPacket->bl_contents;
  275.     ck=0;
  276.     for(i=0; i<128; i++) {
  277.       ck=ck+buf[i];
  278.     }
  279.     lastPacket->bl_check.cksum=(ck&0xff);
  280.     xpr_swrite(&v->io,&lastPacket->bl_start,132);
  281.   } else  {
  282.     lastPacket->bl_start=SOH;
  283.     lastPacket->bl_check.crc=
  284.         compute_crc(lastPacket->bl_contents,128);
  285.     xpr_swrite(&v->io,&lastPacket->bl_start,133);
  286.   }
  287.   xpr_sflush(&v->io);
  288.   SPrintF(v->scratch,"Sending block #%ld %s -",blocknum,
  289.                    (!ckmode ? "Check" : "CRC") );
  290.   updmsg(v,v->scratch); /* sending block # */
  291. }
  292.  
  293. long sendXFile(struct Vars *v,char *filename)
  294. {
  295.   struct WindowX myWindow;
  296.   block *lastPacket;
  297.   int   badCount,retry;
  298.   void *workFILE; /* XPR handle on file */
  299.   char  ckmode;         /* a 0 for checksum, 1 for CRC */
  300.   int   state;
  301.   short eof=0;
  302.   int   blocknum;
  303.   short count;
  304.  
  305.   if((workFILE=(void *)xpr_fopen(&v->io,filename,"r"))==NULL) {
  306.     SPrintF(v->scratch, "Couldn't open file %s",filename);
  307.     updmsg(v,v->scratch);
  308.     return(ERROR);
  309.   }
  310.   else { /* We could open the file */
  311.     
  312.     (void) AllocWindowX(&myWindow);  /* TODO: Do checks for not allocated */
  313.  
  314. /*
  315.  | XS0 | WaitTeLnk| 1 over 40-60 seconds    | report sender timeout   | exit|
  316.  |     |          | 2 over 2 tries          | note TeLink block failed| XS1 |
  317.  |     |          | 3 NAK or "C" received   | send TeLink, incr tries | XS0 |
  318.  |     |          | 4 ACK received          | TeLink ok, set crc/cksm | XS2 |
  319.   really like this:
  320.   XS0a              1 timeout (40-60 sec)                               exit
  321.                     2 NAK or "C"            | send TeLink block         XS0b
  322.  
  323.   XS0b              1 timeout (40-60 sec)                               exit
  324.                     2 NAK or "C"            | send TeLink block         XS0c
  325.                     3 ACK                   | TeLink ok, set crc/cksm   XS2
  326.   XS0c              1 timeout (40-6- sec)                               exit
  327.                     2 NAK or "C"            | note TeLink block failed  fail?
  328.                     3 ACK                   | TeLink ok                 XS2 */
  329.  
  330.  
  331.     if((lastPacket=(block *)RemHead(&myWindow.wx_freeblocks))==NULL) {
  332.            updmsg(v,"Fully Tilted Head");
  333.            FreeWindowX(&myWindow);
  334.            xpr_fclose(&v->io,workFILE);
  335.            return(ERROR);
  336.     }
  337.  
  338.     retry=9;
  339.     state=GOTNAK;
  340.     if (!(v->outfiles) || (v->option_f=='Y')) {
  341.       while((state!=GOTACK) && (retry--)) {
  342.         char temp[2];
  343.         ckmode=((v->option_o=='T') ? 0 :
  344.                 (retry<5 && (v->option_o!='S')) ? 0 : 
  345.                              (v->option_b=='Y') ? 2 : 1);
  346.  
  347.         makeTelinkHeader(lastPacket->bl_contents,filename,
  348.                        xpr_finfo(&v->io,filename,1),
  349.                        0,
  350.                        ckmode);
  351.         sendXPacket(v,ckmode,lastPacket,0);
  352.         state=xpr_sread(&v->io,temp,1,5000000);
  353.         if(state==NODCD) {
  354.           FreeWindowX(&myWindow);
  355.           xpr_fclose(&v->io,workFILE);
  356.           return(NODCD);
  357.         }
  358.         if(state && (temp[0]==ACK)) state=GOTACK;
  359.       }
  360.       SPrintF(v->scratch,"retry %ld ckmode %ld  Filename:%s",retry,ckmode,
  361.                            filename);
  362.       updmsg(v,v->scratch);
  363.     }
  364.     if(state!=GOTACK) { /* Header Block Failed */
  365.           updmsg(v,"Header block failed!");
  366.           if(!(v->outfiles) && (v->option_m=='Y')) {
  367.             /* It's ok, it is the mail bundle */
  368.             goto send_file;
  369.           }
  370.           else if(v->option_7=='Y') {
  371.             goto send_file;    /* We relayed the file name another way. */
  372.           }
  373.           else {               /* Too, bad. I don't do UNKNOWN.$$$ */
  374.             FreeWindowX(&myWindow);
  375.             xpr_fclose(&v->io,workFILE);
  376.             return(ERROR);
  377.           }
  378.     }
  379.     /* header was successfull! */
  380.     SPrintF(v->scratch,"%s header block sent!",
  381.              (ckmode ? "SeaLink" : "Telink"));
  382.     updmsg(v,v->scratch);
  383.  
  384.    send_file:
  385.     blocknum=1;
  386.     badCount=0;
  387.     xpr_sflush(&v->io);
  388.  
  389.     while(!eof) {
  390.       { short i;
  391.  
  392.         if((i=xpr_fread(&v->io,lastPacket->bl_contents, 1,128,workFILE))!=128) {
  393.           for(;i<128; i++) {
  394.             lastPacket->bl_contents[i]=SUB;
  395.           }
  396.           eof=1;
  397.         }
  398.       }
  399. /*
  400.  | XS2 | SendBlock| 1 more data available   | send next data block    | XS3 |
  401.  |     |          |                         |   as checksum or crc    |     |
  402.  |     |          | 2 last block has gone   | send EOT                | XS4 |
  403.  | XS3 | WaitACK  | 1 10 retries or 1 minute| report send failed      | exit|
  404.  |     |          | 2 ACK received          |                         | XS2 |
  405.  |     |          | 3 NAK (or C if 1st blk) | resend last block       | XS3 |
  406.  | XS4 | WaitEnd  | 1 10 retries or 1 minute| report send failed      | exit|
  407.  |     |          | 2 ACK received          | report send successful  | exit|
  408.  |     |          | 3 NAK received          | resend EOT              | XS4 |
  409.  */
  410.  
  411.       state=GOTNAK;
  412.       count=0;
  413.       while(state==GOTNAK) {
  414.         char temp[2];
  415.  
  416.         xpr_sflush(&v->io); /* temporary for non-sealink sends */
  417.         sendXPacket(v,1,lastPacket,blocknum);
  418.         state=0;
  419.         while (state>-1) {
  420.           state=xpr_sread(&v->io,temp,1,4000000);
  421.           if(state==-1) {
  422.             updmsg(v,"Lost carrier!");
  423.             xpr_fclose(&v->io,workFILE);
  424.             FreeWindowX(&myWindow);
  425.             return(NODCD);
  426.           }
  427.           if(state==1)
  428.             if((temp[0]&0xff)==ACK) {
  429.               state=GOTACK;
  430.               updmsg(v,"R:ACK");
  431.             } else if ((temp[0]&0xff)==NAK) {
  432.               updmsg(v,"R:NAK");
  433.               badCount++;
  434.               state=GOTNAK;
  435.        } else {
  436.               SPrintF(v->scratch,"R:Junk(%ld)\n",temp[0]&0xff);
  437.               updmsg(v,v->scratch);
  438.        }
  439.       else {
  440.             state=GOTNAK;
  441.             updmsg(v,"TIME");
  442.             badCount++;
  443.           }
  444.           if((state==GOTNAK) && count++>10) {
  445.             updmsg(v,"Too many retries. Line bad.");
  446.             xpr_fclose(&v->io,workFILE);
  447.             FreeWindowX(&myWindow);
  448.             return(ERROR);
  449.           }
  450.     }
  451.       }
  452.       blocknum++;
  453.     }
  454.     xpr_fclose(&v->io,workFILE);
  455.     count=0;
  456.     state=TIMEOUT;
  457.     while((state==GOTNAK) || (state==TIMEOUT)) {
  458.       char temp[2];
  459.  
  460.       if(state==TIMEOUT) {
  461.         temp[0]=EOT;
  462.         xpr_swrite(&v->io,temp,1);
  463.         updmsg(v,"EOF/EOT");
  464.       }
  465.       state=xpr_sread(&v->io,temp,1,2000000);
  466.       SPrintF(v->scratch,"state:%ld, c:%ld",state,temp[0]&0xff);
  467.       updmsg(v,v->scratch);
  468.  
  469.       if(state==-1) return(NODCD);
  470.       if(state && ((temp[0]&0xff)==ACK)) state=GOTACK;
  471.       else if(state) state=GOTNAK;
  472.       else {
  473.         state=TIMEOUT;
  474.         if(count++>9) {
  475.           updmsg(v,"Too many retries. Can't end transfer.");
  476.           FreeWindowX(&myWindow);
  477.           return(ERROR);
  478.         }
  479.       }
  480.     }
  481.   end:
  482.     FreeWindowX(&myWindow);
  483.     return(OK);
  484.   }
  485. }
  486.  
  487. long sendmdm7(struct Vars *v,char *filename)
  488. {
  489.   long i,state;
  490.   UBYTE mdm7name[16],*tempf,cksum,c,temp[2],temp1[2];
  491.  
  492.   /* get basename */
  493.   for(tempf=filename+strlen(filename);
  494.       tempf!=filename && *(tempf-1)!='/' && *(tempf-1)!=':';
  495.       tempf--);
  496.  
  497. #ifdef KDEBUG
  498.   KPrintF("Filename: '%s' BaseName '%s'\n",filename,tempf);
  499. #endif
  500.  
  501.   for(i=0; i<11; i++) mdm7name[i]=' ';
  502.   mdm7name[11]='\0';
  503.   for(i=0; i<11 && *tempf!='\0'; i++) {
  504.     if(*tempf=='.') {
  505.       i=7;
  506.     }
  507.     else {
  508.       mdm7name[i]=toupper(*tempf);
  509.     }
  510.     tempf++;
  511.   }
  512.   cksum=0;
  513.   for(i=0; i<11; i++ ) {
  514.     cksum+=mdm7name[i];
  515.   }
  516.   cksum+=SUB;
  517.   cksum=cksum&0xff;
  518.   mdm7name[11]='\0';
  519.  
  520.  
  521. /*
  522.  |-----+----------+-------------------------+-------------------------+-----|
  523.  | MS0 | WaitNak  | 1 20 retries or 1 minute| filename send failed    | exit|
  524.  |     |          | 2 NAK received          | send ACK & 1st ch of fn | MS1 |
  525.  |-----+----------+-------------------------+-------------------------+-----|
  526.  | MS1 | WaitChAck| 1 ACK rcd, fname done   | send SUB = 1AH          | MS2 |
  527.  |     |          | 2 ACK rcd, fname ~done  | send next ch of fname   | MS1 |
  528.  |     |          | 3 other char or 1 sec   | send "u", incr retry cnt| MS0 |
  529.  |-----+----------+-------------------------+-------------------------+-----|
  530. */
  531.  
  532.   xpr_sflush(&v->io);
  533.   temp1[0]=ACK;
  534.   xpr_swrite(&v->io,temp1,1);
  535.  
  536.   updmsg(v,"MDM7 filename send");
  537.  
  538.   for(i=0; i<11; i++) {
  539.     xpr_swrite(&v->io,&mdm7name[i],1);
  540.     state=xpr_sread(&v->io,temp,1,5000000);
  541.     if(state==1 && (temp[0]&0xff==CAN)) {
  542.       temp1[0]=ACK;
  543.       xpr_swrite(&v->io,temp1,1);
  544.       return(GOTEOT);
  545.     }
  546.     else if(state!=1 || ((temp[0]&0xff) != ACK))
  547.       break;
  548.   }
  549.  
  550. #ifdef KDEBUG
  551.   KPrintF("Sread1: %ld c=%ld\n",state,temp[0]&0xff);
  552. #endif
  553.  
  554.   if((state==1) && ((temp[0]&0xff)==ACK)) {
  555. /*
  556.  | MS2 | WaitCksm | 1 cksum recd and ok     | send ACK, report fn ok  | exit|
  557.  |     |          | 2 cksum recd but bad    | send "u", incr retry cnt| MS0 |
  558.  |     |          | 3 no cksum in 1 sec     | send "u", incr retry cnt| MS0 |
  559.  */
  560.     temp1[0]=SUB;
  561.     xpr_swrite(&v->io,temp1,1);
  562.     state=xpr_sread(&v->io,temp,1,3000000);
  563. #ifdef KDEBUG
  564.   KPrintF("Sread2: %ld c=%ld\n",state,temp[0]&0xff);
  565. #endif
  566.     if(state==1)
  567.       if((c=temp[0]&0xff)==cksum) {
  568.         temp1[0]=ACK;
  569.         xpr_swrite(&v->io,temp1,1);
  570.         return(sendXFile(v,filename));
  571.       } else {
  572.         SPrintF(v->scratch,"Modem7 checksum failed: %ld vs %ld",c,cksum);
  573.         updmsg(v,v->scratch);
  574.       }
  575.     else
  576.      updmsg(v,"Time/DCD");
  577.   }
  578.   temp1[0]='u';
  579.   xpr_swrite(&v->io,temp1,1);
  580.   updmsg(v,"Modem7 Filename send failed");
  581.   return(MDM7BAD);
  582. }
  583.